package com.example.test;

import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

public class Utils {

	//Question1
	/**
	 * Question1, sort by firstName + lastName + ext,
	 * if firstName is the same then sort by lastName and
	 * ext, please note lastName and ext can be empty
	 * string or null.
	 *
	 **/
	public static List<Extension> sortByName(List<Extension> extensions) {


		if (extensions.equals(null)) {
			return extensions;
		}

//		nulls first
		extensions.stream().sorted(Comparator.nullsFirst(Comparator.comparing(Extension::getLastName))
				.thenComparing(Comparator.nullsFirst(Comparator.comparing(Extension::getLastName)))
				.thenComparing(Comparator.nullsFirst(Comparator.comparing(Extension::getExt)))
		);


//		nulls last
//		extensions.stream().sorted(Comparator.nullsLast(Comparator.comparing(Extension::getLastName))
//				.thenComparing(Comparator.nullsLast(Comparator.comparing(Extension::getLastName)))
//				.thenComparing(Comparator.nullsLast(Comparator.comparing(Extension::getExt)))
//		);


		return extensions;
	}


	//Question
	/**
	 * Question2, sort extType, extType is a string and can
	 * be "User", "Dept", "AO", "TMO", "Other",
	 * sort by User > Dept > AO > TMO > Other;
	 *
	 **/
	public static List<Extension> sortByExtType(List<Extension> extensions) {
		if (extensions.equals(null)) {
			return extensions;
		}
		List<String> strings = Arrays.asList(StringUtils.split("User>Dept>AO>TMO>Other", ">"));
		return extensions.stream().sorted(Comparator.comparing(x -> strings.indexOf(x.getExtType()))).collect(toList());

	}
	
	//Question3
	/**
	 * Question3, sum all sales items by quarter
	 *
	 **/
	public static List<QuaterSalesItem> sumByQuarter(List<SaleItem> saleItems) {
		if (saleItems.equals(null)) {
			return null;
		}
		 List<QuaterSalesItem> collect = saleItems.parallelStream().map(x -> {
			QuaterSalesItem quaterSalesItem = new QuaterSalesItem();
			quaterSalesItem.setTotal(x.getSaleNumbers());
			saleItemMap2QuaterSalesItem(x, quaterSalesItem);
			return quaterSalesItem;
		}).collect(Collectors.groupingBy(QuaterSalesItem::getQuarter, Collectors.summingDouble(QuaterSalesItem::getTotal)))
				.entrySet().parallelStream().map(x -> {
					QuaterSalesItem quaterSalesItem = new QuaterSalesItem();
					quaterSalesItem.setTotal(x.getValue());
					quaterSalesItem.setQuarter(x.getKey());
					return quaterSalesItem;
				}).collect(toList());

		return collect;
	}
	
    //Question4
	/**
	 * Question4, max all sales items by quarter
	 *
	 **/
	public static List<QuaterSalesItem> maxByQuarter(List<SaleItem> saleItems) {
		if (saleItems.equals(null)) {
			return null;
		}
		final List<QuaterSalesItem> collect = saleItems.parallelStream().map(x -> {
			QuaterSalesItem quaterSalesItem = new QuaterSalesItem();
			quaterSalesItem.setTotal(x.getSaleNumbers());
			saleItemMap2QuaterSalesItem(x, quaterSalesItem);
			return quaterSalesItem;
		}).collect(Collectors.groupingBy(
				QuaterSalesItem::getQuarter,
				Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingDouble(QuaterSalesItem::getTotal)),
						Optional::get)
		)).entrySet().parallelStream().map(x -> x.getValue()).collect(toList());



		return collect;
	}



	//Question5
	/**
	 * We have all Keys: 0-9;
	 * usedKeys is an array to store all used keys like :[2,3,4];
	 * We want to get all unused keys, in this example it would be: [0,1,5,6,7,8,9,]
	 */
	
	public static int[] getUnUsedKeys(int[] allKeys, int[] usedKeys) {
		if (usedKeys.equals(null)||usedKeys.length==0||allKeys.equals(null)||usedKeys.length==0) {
			return allKeys;
		}else if (usedKeys.length==allKeys.length){
			return new int[0];
		}

//		Time complexity: O(nlogn)
		Set<Integer> set = new HashSet<>();
		Arrays.sort(allKeys);
		Arrays.sort(usedKeys);
		int i = 0;
		int j = 0;
		int m = 0;
		while (i < allKeys.length && j < usedKeys.length) {
			if (allKeys[i] < usedKeys[j]) {
				if (i==0) {
					set.add(allKeys[i]);
				}else if (allKeys[i]!=allKeys[i-1]) {
					set.add(allKeys[i]);
				}
				i++;
			} else if (allKeys[i] > usedKeys[j]) {
				j++;
			} else {
				i++;
				j++;
				m++;
			}
		}
//		members of the two arrays  may be repeat
		if (allKeys.length>m) {
			for (int i_ = i; i_ < allKeys.length; i_++) {
				set.add(allKeys[i_]);
			}
		}
		int[] result = new int[set.size()];
		int k = 0;
		for (Integer num : set) {
			result[k++] = num;
		}
		return result;

//		Time complexity: O(n)

		/*Set<Integer> set = new HashSet<>();
		Set<Integer> except = new HashSet<>();
		for (int i = 0; i < usedKeys.length; i++) {
			set.add(allKeys[i]);
		}
		for (int i = 0; i < allKeys.length; i++) {
			if (!set.contains(allKeys[i])) {
				except.add(allKeys[i]);
			}
		}
		int[] result = new int[except.size()];
		int i = 0;
		for (Integer num : except) {
			result[i++] = num;
		}
		return result;*/




	}

	public static void main(String[] args) {

	}

	private static void saleItemMap2QuaterSalesItem(SaleItem x, QuaterSalesItem quaterSalesItem) {
		if (1 <= x.getMonth() && 3 >= x.getMonth()) {
			quaterSalesItem.setQuarter(1);
		} else if (4 <= x.getMonth() && 6 >= x.getMonth()) {
			quaterSalesItem.setQuarter(2);
		} else if (7 <= x.getMonth() && 9 >= x.getMonth()) {
			quaterSalesItem.setQuarter(3);
		} else {
			quaterSalesItem.setQuarter(4);
		}
	}
	
}
